home *** CD-ROM | disk | FTP | other *** search
/ Video Toaster 4.2 / Video Toaster v4.2.iso / programs / documentation / lightwave / sdk / sample / spikey / spikey.c < prev    next >
Encoding:
C/C++ Source or Header  |  1995-07-05  |  6.1 KB  |  264 lines

  1. /*
  2.  * SPIKEY.C -- Modeler Plugin Mesh Edit
  3.  *           Make a polygonal object spikey while subdividing
  4.  *
  5.  * written by Stuart Ferguson
  6.  * last revision  12/6/94
  7.  */
  8. #include <splug.h>
  9. #include <lwmod.h>
  10. #include <string.h>
  11. #include <stdio.h>
  12. #include <math.h>
  13.  
  14.  
  15.  
  16. /*
  17.  * Local information packet.  This includes the mesh edit context, monitor,
  18.  * and polygon count.  Also holds the spike factor which might be variable.
  19.  */
  20. typedef struct st_MyData {
  21.     MeshEditOp        *op;
  22.     Monitor            *mon;
  23.     unsigned int         count;
  24.     double             spike;
  25. } MyData;
  26.  
  27.  
  28. /*
  29.  * Utility to return the distance between two 3D points.
  30.  */
  31.     static double
  32. Dist3D (
  33.     double             v1[3],
  34.     double             v2[3])
  35. {
  36.     double             d, z;
  37.     int             i;
  38.  
  39.     d = 0.0;
  40.     for (i = 0; i < 3; i++) {
  41.         z = v1[i] - v2[i];
  42.         d += z * z;
  43.     }
  44.     return sqrt (d);
  45. }
  46.  
  47.  
  48. /*
  49.  * This is called for all the polygons as a preliminary pass to count the
  50.  * affected ones.  Polygons are only processed if they are faces, they are
  51.  * selected and they have at least three vertices.
  52.  */
  53.     static EDError
  54. CountPols (
  55.     MyData            *dat,
  56.     const PolygonInfo    *pi)
  57. {
  58.     if ((pi->flags & (PPDF_SELECT | PPDF_CURVE)) == PPDF_SELECT
  59.       && pi->numPnts >= 3)
  60.         dat->count ++;
  61.  
  62.     return EDERR_NONE;
  63. }
  64.  
  65.  
  66. /*
  67.  * This is called for all the polygons to delete them and replace them with
  68.  * triangles around a centeral displaced point.  The check for which ones
  69.  * to process and which to skip is the same as above.
  70.  */
  71.     static EDError
  72. Subdivide (
  73.     MyData            *dat,
  74.     const PolygonInfo    *pi)
  75. {
  76.     MeshEditOp        *op = dat->op;
  77.     EditStateRef         s = op->state;
  78.     PointInfo        *vi;
  79.     double             cen[3], norm[3], d;
  80.     PntID             cg;
  81.     PntID             vl[3];
  82.     int             i;
  83.  
  84.     if ((pi->flags & (PPDF_SELECT | PPDF_CURVE)) != PPDF_SELECT
  85.       || pi->numPnts < 3)
  86.         return EDERR_NONE;
  87.  
  88.     /*
  89.      * Count this polygon in the aggregate for the monitor.  The
  90.      * step function returns True if the user has requested an abort,
  91.      * which we can propogate by returning the appropriate code.
  92.      */
  93.     if (dat->mon && (*dat->mon->step) (dat->mon->data, 1))
  94.         return EDERR_USERABORT;
  95.  
  96.     /*
  97.      * Compute the CG of the polygon vertices as `cen.'
  98.      */
  99.     cen[0] = cen[1] = cen[2] = 0.0;
  100.     for (i = 0; i < pi->numPnts; i++) {
  101.         vi = (*op->pointInfo) (s, pi->points[i]);
  102.         if (!vi)
  103.             return EDERR_NOMEMORY;
  104.  
  105.         cen[0] += vi->position[0];
  106.         cen[1] += vi->position[1];
  107.         cen[2] += vi->position[2];
  108.     }
  109.     cen[0] = cen[0] / pi->numPnts;
  110.     cen[1] = cen[1] / pi->numPnts;
  111.     cen[2] = cen[2] / pi->numPnts;
  112.  
  113.     /*
  114.      * Compute the average distance from a polygon vertex to
  115.      * the center point.
  116.      */
  117.     d = 0.0;
  118.     for (i = 0; i < pi->numPnts; i++) {
  119.         vi = (*op->pointInfo) (s, pi->points[i]);
  120.         if (!vi)
  121.             return EDERR_NOMEMORY;
  122.  
  123.         d += Dist3D (vi->position, cen);
  124.     }
  125.     d = d / pi->numPnts;
  126.  
  127.     /*
  128.      * Translate the center point out of the polygon's plane by this
  129.      * average distance times the spikeyness factor.  This translation
  130.      * can only be done if the polygon has a valid normal.
  131.      */
  132.     d *= dat->spike;
  133.     if (d && (*op->polyNormal) (op->state, pi->pol, norm)) {
  134.         cen[0] += norm[0] * d;
  135.         cen[1] += norm[1] * d;
  136.         cen[2] += norm[2] * d;
  137.     }
  138.  
  139.     /*
  140.      * Create a new point at the offset center position.
  141.      */
  142.     cg = (*op->addPoint) (s, cen);
  143.     if (!cg)
  144.         return EDERR_NOMEMORY;
  145.  
  146.     /*
  147.      * Loop over points in the polygon and create new triangles
  148.      * from each pair to the center.  We use `addPoly' rather than
  149.      * `addTri' since we want to preserve the original polygon
  150.      * surface and sidedness.  Note the "modulo numPnts" to make
  151.      * the point index wrap around the end of the point array.
  152.      */
  153.     vl[0] = cg;
  154.     for (i = 0; i < pi->numPnts; i++) {
  155.         vl[1] = pi->points[i];
  156.         vl[2] = pi->points[(i + 1) % pi->numPnts];
  157.         if (!(*op->addPoly) (s, pi->surface, 3, vl))
  158.             return EDERR_NOMEMORY;
  159.     }
  160.  
  161.     /*
  162.      * Delete the orginal and we're done.
  163.      */
  164.     return ((*op->remPoly) (op->state, pi->pol));
  165. }
  166.  
  167.  
  168. /*
  169.  * Main entry point for mesh operation.
  170.  */
  171.     XCALL_(int)
  172. Activate (
  173.     long             version,
  174.     GlobalFunc        *global,
  175.     MeshEditBegin        *local,
  176.     void            *serverData)
  177. {
  178.     MeshEditOp        *op;
  179.     DynaMonitorFuncs    *mfunc;
  180.     MyData             dat;
  181.     EDError             err;
  182.  
  183.     /*
  184.      * Check interface version.
  185.      */
  186.     XCALL_INIT;
  187.     if (version != 1)
  188.         return AFUNC_BADVERSION;
  189.  
  190.     /*
  191.      * Get global data -- monitor functions.
  192.      */
  193.     mfunc = (*global) ("LWM: Dynamic Monitor", GFUSE_TRANSIENT);
  194.     if (!mfunc)
  195.         return AFUNC_BADGLOBAL;
  196.  
  197.     /*
  198.      * Attempt to begin edit operation.  If the startup fails we still
  199.      * return OK, but just don't do anything.
  200.      */
  201.     op = (*local) (0, 0, OPSEL_USER);
  202.     if (!op)
  203.         return AFUNC_OK;
  204.  
  205.     /*
  206.      * Count the polygons that will be affected by the operation.  This
  207.      * has to be done with an explicit scan and it can fail.  The time
  208.      * for a scan of this type should be small enough to not be very
  209.      * significant.
  210.      */
  211.     dat.op = op;
  212.     dat.count = 0;
  213.     err = (*op->polyScan) (op->state, CountPols, &dat, OPLYR_PRIMARY);
  214.     if (err) {
  215.         (*op->done) (op->state, err, 0);
  216.         return AFUNC_OK;
  217.     }
  218.  
  219.     /*
  220.      * Start the monitor.  If we can create a monitor, initialize it
  221.      * with the polygon count.
  222.      */
  223.     dat.mon = (*mfunc->create) ("Spikey Subdivide", NULL);
  224.     if (dat.mon)
  225.         (*dat.mon->init) (dat.mon->data, dat.count);
  226.  
  227.     /*
  228.      * Process the polygons in a second scan through the polygon
  229.      * database.  The spikiness parameter will just be fixed,
  230.      * although it could easily be set by a requester.
  231.      *
  232.      * We will alter polygons in the primary layer only since we
  233.      * can only create new data in this layer.
  234.      */
  235.     dat.spike = 2.0;
  236.     err = (*op->polyScan) (op->state, Subdivide, &dat, OPLYR_PRIMARY);
  237.  
  238.     /*
  239.      * End the monitor whether we completed successfully or not.
  240.      */
  241.     if (dat.mon) {
  242.         (*dat.mon->done) (dat.mon->data);
  243.         (*mfunc->destroy) (dat.mon);
  244.     }
  245.  
  246.     /*
  247.      * Complete the operation by calling `done.'  We pass the error
  248.      * code if there was one, or NONE.  We also want to select any
  249.      * new data if there was data selected to start with.  This is
  250.      * important for maintaining the user's idea that the same stuff
  251.      * is selected even though we replaced each polygon with several
  252.      * new ones.
  253.      */
  254.     (*op->done) (op->state, err, EDSELM_SELECTNEW);
  255.     return AFUNC_OK;
  256. }
  257.  
  258.  
  259. /*
  260.  * Globals necessary to declare the class and name of this plugin server.
  261.  */
  262. char        ServerClass[] = "MeshDataEdit";
  263. char        ServerName[]  = "Demo_MakeSpikey";
  264.